﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using Citi.Helpers;
using Citi.Scheduler.Domain;

namespace Citi.Scheduler.WebUi.Helpers
{
    public class ChartsHelper
    {
        public static HighChartsHelper.ChartInformation GetErrorDataChart(IEnumerable<RoutineExecution> executions)
        {
            var errorsCategories = GetExecutionStatus(executions);

            return new HighChartsHelper.ChartInformation
            {
                Categories = errorsCategories.Select(x => x.GetDescription()).ToArray(),
                Series = errorsCategories.Select(status => FillErrorSerie(executions, status)).ToArray()
            };
        }

        private static List<RoutineExecutionStatus> GetExecutionStatus(IEnumerable<RoutineExecution> executions)
        {
            var errorsCategories = executions
                .Where(x => x.RoutineExecutionHistories.Any())
                .Select(x => (RoutineExecutionStatus)x.RoutineExecutionHistories
                                                       .OrderBy(y => y.Date).Last().Status).Distinct().ToList();
            return errorsCategories;
        }

        public static HighChartsHelper.ChartInformation GetErrorMachineDataChart(IEnumerable<RoutineExecution> executions)
        {
            var executed = executions.Where(x => x.EndsOn.HasValue && x.StartsOn.HasValue);
            var machines = executed.Select(x => x.Machine).Distinct().ToList();
            var chartInformation = GetErrorDataChart(executed);

            foreach (var serie in chartInformation.Series)
            {
                var status = (RoutineExecutionStatus)Enum.Parse(typeof(RoutineExecutionStatus), serie.Name);
                var statusExecutions = executions.Where(x => x.RoutineExecutionHistories.OrderBy(y => y.Date).Last().Status
                    == (int)status);

                serie.Drilldown = new HighChartsHelper.ChartInformation
                {
                    Categories = machines.Select(x => x.HostName).ToArray(),
                    Series = new HighChartsHelper.Serie[1]
                };

                var list = machines.Select(machine => statusExecutions.Count(x => x.MachineId == machine.Id)).Cast<object>().ToList();
                serie.Drilldown.Series[0] = new HighChartsHelper.Serie { Data = list.ToArray(), Name = serie.Name };

                // serie.Drilldown.Series[machines.IndexOf(machine)].Data = statusExecutions.Where(x => x.MachineId == machine.Id).ToArray();
            }

            return chartInformation;
        }

        public static HighChartsHelper.Serie FillErrorSerie(IEnumerable<RoutineExecution> executions, RoutineExecutionStatus status)
        {
            return new HighChartsHelper.Serie
                {
                    Name = status.GetDescription(),
                    Data = new object[] { executions.Count(x => x.RoutineExecutionHistories.OrderBy(y => y.Date).Last().Status == (int)status) },
                    Color = GetColorByStatus(status)
                };
        }

        private static Color? GetColorByStatus(RoutineExecutionStatus status)
        {
            return status == RoutineExecutionStatus.Executed ? Color.Green : status == RoutineExecutionStatus.Error ? Color.Red : new Color?();
        }

        public static HighChartsHelper.ChartInformation GetRuntimeExecutionChart(IEnumerable<RoutineExecution> executions)
        {
            var routines = GetExecutionsExecutionChart(executions);
            var executed = executions.Where(x => x.EndsOn.HasValue && x.StartsOn.HasValue).ToList();
            var categories = executed.Select(x => x.ScheduledDateTime.ToString("dd/MM/yy")).Distinct().ToList().Select(x=> string.Empty).ToList();

            return new HighChartsHelper.ChartInformation
            {
                Categories = categories.ToArray(),
                Series = routines.Select(routine => FillExecutionSerie(executed, routine, categories)).ToArray()
            };
        }

        public static HighChartsHelper.ChartInformation GetMemoryUsageChart(Dictionary<RoutineExecution, IEnumerable<MemoryUsage>> memoryUsages)
        {
            var usages = new List<MemoryUsage>();

            foreach (var memoryUsage in memoryUsages)
                usages.AddRange(memoryUsage.Value);

            var categories  = usages.Select(x => x.Seconds.ToString()).ToList();

            return new HighChartsHelper.ChartInformation
            {
                Categories = categories.ToArray(),
                Series = memoryUsages.Select(x => new HighChartsHelper.Serie{ Name = x.Key.Routine.Name, Data = x.Value.Select(y=> (object) y.Size).ToArray()}).ToArray()
            };
        }

        private static IEnumerable<Routine> GetExecutionsExecutionChart(IEnumerable<RoutineExecution> executions)
        {
            var routines = executions.Where(x => x.EndsOn.HasValue && x.StartsOn.HasValue)
                                     .OrderBy(x => x.ScheduledDateTime)
                                     .Select(x => x.Routine).Distinct().ToList();
            return routines;
        }

        public static HighChartsHelper.Serie FillExecutionSerie(IEnumerable<RoutineExecution> executions, Routine routine, List<string> categories)
        {
            var executed = executions.Where(x => x.EndsOn.HasValue && x.StartsOn.HasValue && x.RoutineId == routine.Id).ToList();

            var data = new List<object>();
            categories.ForEach(x =>
                {
                    var execution = executed.FirstOrDefault(y => y.ScheduledDateTime.ToString("dd/MM/yy") == x);
                    data.Add(execution != null
                        ? new[] { x, (object)Math.Round((execution.EndsOn.Value - execution.StartsOn.Value).TotalMinutes, 2) }
                        : new object[] { x, null });
                });

            return new HighChartsHelper.Serie
                {
                    Name = routine.Name,
                    Data = data.ToArray()
                    //Data = executed.Select(x => (object)Math.Round((x.EndsOn.Value - x.StartsOn.Value).TotalMinutes, 2)).ToArray()
                };
        }
    }
}